(function () {
  var Magnifier = function (opt) {
    this.mountedEl = opt.mountedEl;
    this.imgSrc = opt.imgSrc;
    this.imgHeight = opt.imgHeight || 600;
    this.imgWidth = opt.imgWidth || 400;
    this.magHeight = opt.magHeight || 150;
    this.magWidth = opt.magWidth || 150;
    this.scale = opt.scale || 1.5;
  };

  Magnifier.prototype.init = function () {
    this.render();
    this.setOptions(this.getOElements());
    this.bindEvent(this.getOElements());
  };

  Magnifier.prototype.render = function () {
    this.mountedEl.innerHTML = createElement.call(this);
  };

  Magnifier.prototype.getOElements = function () {
    var oMagnifier = this.mountedEl.getElementsByClassName('magnifier')[0],
      oMagWrap = oMagnifier.getElementsByClassName('mag-wrap')[0],
      oMagImg = oMagWrap.getElementsByClassName('mag-img')[0];

    return { oMagnifier, oMagWrap, oMagImg };
  };

  Magnifier.prototype.bindEvent = function (oElements) {
    var { oMagnifier } = oElements;

    addEvent(oMagnifier, 'mouseover', handleMouseOver.bind(this, oElements));
    addEvent(oMagnifier, 'mouseout', handleMouseOut.bind(this, oElements));
  };

  Magnifier.prototype.setOptions = function (oElements) {
    var { oMagnifier, oMagWrap, oMagImg } = oElements;

    setOptionStyle(oMagnifier, 'width', this.imgWidth);
    setOptionStyle(oMagnifier, 'height', this.imgHeight);
    setOptionStyle(oMagImg, 'width', this.imgWidth);
    setOptionStyle(oMagImg, 'height', this.imgHeight);
    setOptionStyle(oMagWrap, 'width', this.magWidth);
    setOptionStyle(oMagWrap, 'height', this.magHeight);

    //设置用户配置的缩放比例
    oMagWrap.style.transform = `scale(${this.scale})`;
  };

  function createElement() {
    return `
      <div class="magnifier">
        <div class="mag-wrap">
          <img class="mag-img" src="${this.imgSrc}" alt="" />
        </div>
        <a href="" class="img-lk">
          <img src="${this.imgSrc}" alt="" class="static-img" />
        </a>
    </div>
    `;
  }

  function handleMouseOver(oElements, e) {
    var { oMagWrap } = oElements;

    //当鼠标进入oMagnifier盒子区域时显示放大镜的盒子
    oMagWrap.className = 'mag-wrap show';
    //放大镜移动逻辑程序
    magMove(oElements, e);
    //一个特殊的方法可以避免使用两个以上事件的绑定，性能上也有优势。
    //同时完美解决事件代理的方式和鼠标滑入滑出绑定所产生的冲突。
    addEvent(document, 'mousemove', handleMouseMove.bind(this, oElements));
  }

  function handleMouseMove(oElements, e) {
    var e = e || window.event;
    //鼠标经过时同样做MouseOver的鼠标放大镜盒子移动操作
    //此移动操作避免多次冒泡引起卡帧抖动
    magMove(oElements, e);
    //隐藏放大镜
    hideMag(oElements, e);
  }

  function handleMouseOut({ oMagWrap }, e) {
    oMagWrap.className = 'mag-wrap';
    removeEvent(document, 'mouseout', handleMouseOut);
  }

  function setMoveStyle(el, dir, val) {
    switch (dir) {
      case 'left':
        el.style.left = val + 'px';
        break;
      case 'top':
        el.style.top = val + 'px';
        break;
      default:
        break;
    }
  }

  //放大镜移动逻辑程序
  function magMove({ oMagnifier, oMagWrap, oMagImg }, e) {
    //实时计算的oMagWrap盒子的宽高
    var magComputeWidth = parseInt(getStyles(oMagWrap, 'width')),
      magComputeHeight = parseInt(getStyles(oMagWrap, 'height')),
      //放大镜盒子中心离盒子自身边缘的距离
      magCenterX = magComputeWidth / 2,
      magCenterY = magComputeHeight / 2,
      // oMagnifier盒子的偏移距离
      imgX = oMagnifier.offsetLeft,
      imgY = oMagnifier.offsetTop,
      //放大镜盒子位移坐标
      //pagePos(e).X是页面鼠标位置
      magMoveX = pagePos(e).X - imgX - magCenterX,
      magMoveY = pagePos(e).Y - imgY - magCenterY;

    //鼠标移动时放大镜跟随，并让鼠标的位置置中于放大镜盒子
    setMoveStyle(oMagWrap, 'left', magMoveX);
    setMoveStyle(oMagWrap, 'top', magMoveY);

    //放大镜盒子移动时，里面的图片需往反方向移动
    setMoveStyle(oMagImg, 'left', -magMoveX);
    setMoveStyle(oMagImg, 'top', -magMoveY);
  }

  //隐藏放大镜
  function hideMag({ oMagnifier, oMagWrap }, e) {
    // oMagnifier盒子的偏移距离
    var imgX = oMagnifier.offsetLeft,
      imgY = oMagnifier.offsetTop,
      //鼠标中心坐标到oMagnifier盒子边缘距离
      mouseXtoOMagDistance = pagePos(e).X - imgX,
      mouseYtoOMagDistance = pagePos(e).Y - imgY,
      //实时计算的oMagnifier盒子的宽高
      magComputeWidth = parseInt(getStyles(oMagnifier, 'width')),
      magComputeHeight = parseInt(getStyles(oMagnifier, 'height'));

    if (
      mouseXtoOMagDistance < 0 ||
      mouseXtoOMagDistance > magComputeWidth ||
      mouseYtoOMagDistance < 0 ||
      mouseYtoOMagDistance > magComputeHeight
    ) {
      oMagWrap.className = 'mag-wrap';
    }
  }

  function setOptionStyle(el, dir, val) {
    switch (dir) {
      case 'width':
        el.style.width = val + 'px';
        break;
      case 'height':
        el.style.height = val + 'px';
        break;
      default:
        break;
    }
  }

  window.Magnifier = Magnifier;
})();
